#pragma once
#include <iostream>
#include <cstring>
#include "data.hpp"
#include <unordered_map>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
namespace client
{
    using namespace std;
    enum
    {
        USAGE_ERROR = 0,
        SOCKET_ERROR,
        BIND_ERROR
    };

    class calclient
    {

    public:
        calclient(const string &ip, const uint16_t port)
            : _sockfd(-1), _serverip(ip), _serverport(port)
        {
        }
        void initClient()
        {

            // 1.跟udp一样 首先进行socket设置
            _sockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (_sockfd < 0)
            {
                cout << "SOCKET error" << endl;
                exit(SOCKET_ERROR);
            }
            cout << "SOCKET success" << endl;
            // 2. tcp的客户端要不要bind？要的！ 要不要显示的bind？不要！这里尤其是client port要让OS自定随机指定！
            // 3. 要不要listen？不要！
            // 4. 要不要accept? 不要！
            // 5. 要什么呢？？要发起链接
        }
        void run()
        {

            // 这里需要connect链接
            struct sockaddr_in peer;
            bzero(&peer, sizeof(peer));
            peer.sin_family = AF_INET;
            peer.sin_port = htons(_serverport);
            peer.sin_addr.s_addr = inet_addr(_serverip.c_str());
            if (connect(_sockfd, (struct sockaddr *)&peer, sizeof(peer)) != 0)
            {
                cerr << "socket connect error" << endl;
            }
            else
            {
                string message;
                string inbuffer;
                while(true)
                {
                    cout << "mycal <<<<<";
                    getline(cin, message);  //1+1 -->用来初始化req的格式
                    Request req = ParseLine(message); 
                    std::string content;
                    req.serialize(&content);
                    cout<<"序列化之后的content: "<<content<<endl;

                    std::string send_message = enLength(content);
                    cout<<"加上分割符的send_message: "<<send_message<<endl;

                    send(_sockfd,send_message.c_str(),send_message.size(),0);

                    // 说明数据发送过去了
                    std::string package,text;
                    if(!recvRequest(_sockfd,inbuffer,&package))
                        continue;
                    cout<<"package= "<<package<<endl;
                    if(!deLength(package,&text)) 
                    {
                        continue;
                    }
                    //exit_code exit_result
                    Response resp;
                    resp.deserialize(text);
                    std::cout<<"exitcode: "<<resp._exitcode<<"_exitrest: "<<resp._exitrest<<endl;

                }
            }
        }
        ~calclient() {}
        //
    Request ParseLine(const std::string &line)
    {
        // 建议版本的状态机！
        //"1+1" "123*456" "12/0"
        int status = 0; // 0:操作符之前，1:碰到了操作符 2:操作符之后
        int i = 0;
        int cnt = line.size();
        std::string left, right;
        char op;
        while (i < cnt)
        {
            switch (status)
            {
            case 0:
            {
                if(!isdigit(line[i]))
                {
                    op = line[i];
                    status = 1;
                }
                else left.push_back(line[i++]);
            }
            break;
            case 1:
                i++;
                status = 2;
                break;
            case 2:
                right.push_back(line[i++]);
                break;
            }
        }
        std::cout << std::stoi(left)<<" " << std::stoi(right) << " " << op << std::endl;
        return Request(std::stoi(left),op, std::stoi(right));
    }
    private:
        int _sockfd;
        string _serverip;
        uint16_t _serverport;
        char _op[5] ={'+','-','*','/','%'};
    };
}